
#include "miracl.h"
#include "mirdef.h"
#include "SM2_ENC.h"
#include "kdf.h"

// 假设这些是您的错误码定义
#define ERR_NOT_VALID_POINT 1
#define ERR_INFINITY_POINT 2
#define ERR_NOT_VALID_ELEMENT 3
#define ERR_ORDER 4
#define ERR_SELFTEST_KG 5
#define ERR_SELFTEST_ENC 6
#define ERR_SELFTEST_DEC 7
#define ERR_ARRAY_NULL 8
#define ERR_C3_MATCH 9

// 假设这些是您的标准数据
unsigned char std_priKey[32] = {
    0x39,0x45,0x20,0x8F,0x7B,0x21,0x44,0xB1,0x3F,0x36,0xE3,0x8A,0xC6,0xD3,0x9F,0x95,
    0x88,0x93,0x93,0x69,0x28,0x60,0xB5,0x1A,0x42,0xFB,0x81,0xEF,0x4D,0xF7,0xC5,0xB8
};
unsigned char std_pubKey[64] = {
    0x09,0xF9,0xDF,0x31,0x1E,0x54,0x21,0xA1,0x50,0xDD,0x7D,0x16,0x1E,0x4B,0xC5,0xC6,
    0x72,0x17,0x9F,0xAD,0x18,0x33,0xFC,0x07,0x6B,0xB0,0x8F,0xF3,0x56,0xF3,0x50,0x20,
    0xCC,0xEA,0x49,0x0C,0xE2,0x67,0x75,0xA5,0x2D,0xC6,0xEA,0x71,0x8C,0xC1,0xAA,0x60,
    0x0A,0xED,0x05,0xFB,0xF3,0x5E,0x08,0x4A,0x66,0x32,0xF6,0x07,0x2D,0xA9,0xAD,0x13
};
unsigned char std_Message[19] = {
    0x65,0x6E,0x63,0x72,0x79,0x70,0x74,0x69,0x6F,0x6E,0x20,0x73,0x74,0x61,0x6E,0x64,0x61,0x72,0x64
};
unsigned char std_Cipher[115] = {
    0x04,0xEB,0xFC,0x71,0x8E,0x8D,0x17,0x98,0x62,0x04,0x32,0x26,0x8E,0x77,0xFE,0xB6,0x41,0x5E,0x2E,0xDE,0x0E,0x07,0x3C,0x0F,0x4F,0x64,0x0E,0xCD,0x2E,0x14,0x9A,0x73,
    0xE8,0x58,0xF9,0xD8,0x1E,0x54,0x30,0xA5,0x7B,0x36,0xDA,0xAB,0x8F,0x95,0x0A,0x3C,0x64,0xE6,0xEE,0x6A,0x63,0x09,0x4D,0x99,0x28,0x3A,0xFF,0x76,0x7E,0x12,0x4D,0xF0,
    0x59,0x98,0x3C,0x18,0xF8,0x09,0xE2,0x62,0x92,0x3C,0x53,0xAE,0xC2,0x95,0xD3,0x03,0x83,0xB5,0x4E,0x39,0xD6,0x09,0xD1,0x60,0xAF,0xCB,0x19,0x08,0xD0,0xBD,0x87,0x66,
    0x21,0x88,0x6C,0xA9,0x89,0xCA,0x9C,0x7D,0x58,0x08,0x73,0x07,0xCA,0x93,0x09,0x2D,0x65,0x1E,0xFA
};

#define SM2_NUMWORD 6  // 假设这是您椭圆曲线的字节长度

int Test_Point(epoint* point)
{
    big x,y,x_3,tmp;
    x=mirvar(0);
    y=mirvar(0);
    x_3=mirvar(0);
    tmp=mirvar(0);
    //test if y^2=x^3+ax+b
    epoint_get(point,x,y);
    power(x, 3, para_p, x_3); //x_3=x^3 mod p
    multiply(x, para_a, x); //x=a*x
    divide(x, para_p, tmp); //x=a*x mod p , tmp=a*x/p
    add(x_3,x,x); //x=x^3+ax
    add(x,para_b,x); //x=x^3+ax+b
    divide(x,para_p,tmp); //x=x^3+ax+b mod p
    power(y, 2, para_p, y); //y=y^2 mod p
    if(mr_compare(x,y)!=0)
    {
        printf("Test_Point failed\n");
        return ERR_NOT_VALID_POINT;
    }
    else
    {
        printf("Test_Point passed\n");
        return 0;
    }
}

int Test_PubKey(epoint *pubKey)
{
    big x,y,x_3,tmp;
    epoint *nP;
    x=mirvar(0);
    y=mirvar(0);
    x_3=mirvar(0);
    tmp=mirvar(0);
    nP=epoint_init();
    //test if the pubKey is the point at infinity
    if (point_at_infinity(pubKey))// if pubKey is point at infinity, return error;
    {
        printf("Test_PubKey failed: Point at infinity\n");
        return ERR_INFINITY_POINT;
    }
    //test if x<p and y<p both hold
    epoint_get(pubKey,x,y);
    if((compare(x,para_p)!=-1) || (compare(y,para_p)!=-1))
    {
        printf("Test_PubKey failed: X or Y exceeds P\n");
        return ERR_NOT_VALID_ELEMENT;
    }
    if(Test_Point(pubKey)!=0)
    {
        printf("Test_PubKey failed: Invalid point\n");
        return ERR_NOT_VALID_POINT;
    }
    //test if the order of pubKey is equal to n
    ecurve_mult(para_n,pubKey,nP); // nP=[n]P
    if (!point_at_infinity(nP)) // if np is point NOT at infinity, return error;
    {
        printf("Test_PubKey failed: Order not equal to N\n");
        return ERR_ORDER;
    }
    printf("Test_PubKey passed\n");
    return 0;
}

int Test_Null(unsigned char array[],int len)
{
    int i=0;
    for(i=0;i<len;i++)
    {
        if (array[i]!=0x00)
            return 0;
    }
    return 1;
}

int SM2_Init()
{
    epoint *nG;
    para_p=mirvar(0);
    para_a=mirvar(0);
    para_b=mirvar(0);
    para_n=mirvar(0);
    para_Gx=mirvar(0);
    para_Gy=mirvar(0);
    para_h=mirvar(0);
G=epoint_init();
nG=epoint_init();
bytes_to_big(SM2_NUMWORD,SM2_p,para_p);
bytes_to_big(SM2_NUMWORD,SM2_a,para_a);
bytes_to_big(SM2_NUMWORD,SM2_b,para_b);
bytes_to_big(SM2_NUMWORD,SM2_n,para_n);
bytes_to_big(SM2_NUMWORD,SM2_Gx,para_Gx);
bytes_to_big(SM2_NUMWORD,SM2_Gy,para_Gy);
bytes_to_big(SM2_NUMWORD,SM2_h,para_h);
ecurve_init(para_a,para_b,para_p,MR_PROJECTIVE);//Initialises GF(p) elliptic curve.
//MR_PROJECTIVE specifying projective coordinates
if (!epoint_set(para_Gx,para_Gy,0,G))//initialise point G
{
printf("SM2_Init failed: Failed to set G point\n");
return ERR_ECURVE_INIT;
}
ecurve_mult(para_n,G,nG);
if (!point_at_infinity(nG)) //test if the order of the point is n
{
printf("SM2_Init failed: Order not equal to N\n");
return ERR_ORDER;
}
printf("SM2_Init passed\n");
return 0;
}

int SM2_KeyGeneration(big priKey,epoint *pubKey)
{
int i=0;
big x,y;
x=mirvar(0);
y=mirvar(0);
ecurve_mult(priKey,G,pubKey);//通过大数和基点产生公钥
epoint_get(pubKey,x,y);
if(Test_PubKey(pubKey)!=0)
{
printf("SM2_KeyGeneration failed\n");
return 1;
}
else
{
printf("SM2_KeyGeneration passed\n");
return 0;
}
}

int SM2_Encrypt(unsigned char* randK,epoint pubKey,unsigned char M[],int klen,unsigned char C[])
{
big C1x,C1y,x2,y2,rand;
epoint C1,kP,S;
int i=0;
unsigned char x2y2[SM2_NUMWORD2]={0};
SM3_STATE md;
C1x=mirvar(0);
C1y=mirvar(0);
x2=mirvar(0);
y2=mirvar(0);
rand=mirvar(0);
C1=epoint_init();
kP=epoint_init();
S=epoint_init();
//Step2. calculate C1=[k]G=(rGx,rGy)
bytes_to_big(SM2_NUMWORD,randK,rand);
ecurve_mult(rand,G,C1); //C1=[k]G
epoint_get(C1,C1x,C1y);
big_to_bytes(SM2_NUMWORD,C1x,C,1);
big_to_bytes(SM2_NUMWORD,C1y,C+SM2_NUMWORD,1);
//Step3. test if S=[h]pubKey if the point at infinity
ecurve_mult(para_h,pubKey,S);
if (point_at_infinity(S))// if S is point at infinity, return error;
{
printf("SM2_Encrypt failed: Point at infinity\n");
return ERR_INFINITY_POINT;
}
//Step4. calculate [k]PB=(x2,y2)
ecurve_mult(rand,pubKey,kP); //kP=[k]P
epoint_get(kP,x2,y2);
//Step5. KDF(x2||y2,klen)
big_to_bytes(SM2_NUMWORD,x2,x2y2,1);
big_to_bytes(SM2_NUMWORD,y2,x2y2+SM2_NUMWORD,1);
SM3_KDF(x2y2 ,SM2_NUMWORD2, klen,C+SM2_NUMWORD3);
if(Test_Null(C+SM2_NUMWORD3,klen)!=0)
{
printf("SM2_Encrypt failed: Null array\n");
return ERR_ARRAY_NULL;
}
//Step6. C2=M^t
for(i=0;i<klen;i++)
{
C[SM2_NUMWORD3+i]=M[i]^C[SM2_NUMWORD3+i];
}
//Step7. C3=hash(x2,M,y2)
SM3_init(&md);
SM3_process(&md,x2y2,SM2_NUMWORD);
SM3_process(&md,M,klen);
SM3_process(&md,x2y2+SM2_NUMWORD,SM2_NUMWORD);
SM3_done(&md,C+SM2_NUMWORD*2);
printf("SM2_Encrypt passed\n");
return 0;
}

int SM2_Decrypt(big dB,unsigned char C[],int Clen,unsigned char M[])
{
SM3_STATE md;
int i=0;
unsigned char x2y2[SM2_NUMWORD2]={0};
unsigned char hash[SM2_NUMWORD]={0};
big C1x,C1y,x2,y2;
epoint C1,S,dBC1;
C1x=mirvar(0);
C1y=mirvar(0);
x2=mirvar(0);
y2=mirvar(0);
C1=epoint_init();
S=epoint_init();
dBC1=epoint_init();
//Step1. test if C1 fits the curve
bytes_to_big(SM2_NUMWORD,C,C1x);
bytes_to_big(SM2_NUMWORD,C+SM2_NUMWORD,C1y);
epoint_set(C1x,C1y,0,C1);
i=Test_Point(C1);
if(i!=0)
{
printf("SM2_Decrypt failed: Invalid point\n");
return i;
}
//Step2. S=[h]C1 and test if S is the point at infinity
ecurve_mult(para_h,C1,S);
if (point_at_infinity(S))// if S is point at infinity, return error;
{
printf("SM2_Decrypt failed: Point at infinity\n");
return ERR_INFINITY_POINT;
}
//Step3. [dB]C1=(x2,y2)
ecurve_mult(dB,C1,dBC1);
epoint_get(dBC1,x2,y2);
big_to_bytes(SM2_NUMWORD,x2,x2y2,1);
big_to_bytes(SM2_NUMWORD,y2,x2y2+SM2_NUMWORD,1);
//Step4. t=KDF(x2||y2,klen)
SM3_KDF(x2y2,SM2_NUMWORD2,Clen-SM2_NUMWORD3,M);
if(Test_Null(M,Clen-SM2_NUMWORD3)!=0)
{
printf("SM2_Decrypt failed: Null array\n");
return ERR_ARRAY_NULL;
}
//Step5. M=C2^t
for(i=0;i<Clen-SM2_NUMWORD3;i++)
M[i]=M[i]^C[SM2_NUMWORD3+i];
//Step6. hash(x2,m,y2)
SM3_init(&md);
SM3_process(&md,x2y2,SM2_NUMWORD);
SM3_process(&md,M,Clen-SM2_NUMWORD3);
SM3_process(&md,x2y2+SM2_NUMWORD,SM2_NUMWORD);
SM3_done(&md,hash);
if(memcmp(hash,C+SM2_NUMWORD*2,SM2_NUMWORD)!=0)
{
printf("SM2_Decrypt failed: C3 mismatch\n");
return ERR_C3_MATCH;
}
else
{
printf("SM2_Decrypt passed\n");
return 0;
}
}

int SM2_ENC_SelfTest()
{
int tmp=0;
unsigned char Cipher[115]={0};
unsigned char M[19]={0};
unsigned char kGxy[SM2_NUMWORD*2]={0};
big ks,x,y;
epoint *kG;
mip= mirsys(1000, 16);
mip->IOBASE=16;
x=mirvar(0);
y=mirvar(0);
ks=mirvar(0);
kG=epoint_init();
bytes_to_big(32,std_priKey,ks); //ks is the standard private key
printf("Starting SM2 self-test...\n");
//initiate SM2 curve
tmp=SM2_Init();
if (tmp!=0)
{
printf("SM2_Init failed with error code %d\n", tmp);
return tmp;
}
//generate key pair
tmp=SM2_KeyGeneration(ks,kG);
if (tmp!=0)
{
printf("SM2_KeyGeneration failed with error code %d\n", tmp);
return tmp;
}
epoint_get(kG,x,y);
big_to_bytes(SM2_NUMWORD,x,kGxy,1);
big_to_bytes(SM2_NUMWORD,y,kGxy+SM2_NUMWORD,1);
if(memcmp(kGxy,std_pubKey,SM2_NUMWORD2)!=0)
{
printf("Public key mismatch\n");
return ERR_SELFTEST_KG;
}
printf("Public key matches standard public key\n");
//encrypt data and compare the result with the standard data
tmp=SM2_Encrypt(std_rand,kG,std_Message,19,Cipher);
if(tmp!=0)
{
printf("SM2_Encrypt failed with error code %d\n", tmp);
return tmp;
}
if(memcmp(Cipher,std_Cipher,19+SM2_NUMWORD3)!=0)
{
printf("Cipher mismatch\n");
return ERR_SELFTEST_ENC;
}
printf("Cipher matches standard cipher\n");
//decrypt cipher and compare the result with the standard data
tmp=SM2_Decrypt(ks,Cipher,115,M);
if(tmp!=0)
{
printf("SM2_Decrypt failed with error code %d\n", tmp);
return tmp;
}
if(memcmp(M,std_Message,19)!=0)
{
printf("Message mismatch\n");
return ERR_SELFTEST_DEC;
}
printf("Message matches standard message\n");
printf("SM2 self-test passed\n");
return 0;
}

int main() {
int result = SM2_ENC_SelfTest();
if (result == 0) {
printf("SM2_SELFTEST completed successfully.\n");
} else {
printf("SM2_SELFTEST failed with error code %d.\n", result);
}
return result;
}



